﻿
package extremefx.ui {
	import extremefx.events.EventArgs;
	import extremefx.modules.css.ComputedStyle;
	import extremefx.modules.css.ICssParser;
	import extremefx.modules.css.ParseCommons;
	import extremefx.modules.css.ParsedProperty;
	import extremefx.modules.css.StyleSheet;
	import extremefx.storage.LoadQeue;
	import extremefx.ui.styles.BitmapInfo;
	import extremefx.ui.styles.UIStyle;
	
	import flash.display.BitmapData;
	import flash.geom.Point;
	import flash.geom.Rectangle;		

	/**
	 * @author Marcelo Volmaro
	 */
	public final class StyleManager implements ICssParser{
		private static var _instance:StyleManager;
		
		private const _bmpCache:Object = {};
		private const _styleSheet:StyleSheet = new StyleSheet();
		
		private const _styles:Array = [];
		private var _inited:Boolean;
		
		public function StyleManager(pPriv:PrivateClass) {
			_styleSheet.setCustomParser(this);
		}
		
		public static function get instance():StyleManager {
			if (!_instance) _instance = new StyleManager(new PrivateClass());
			return _instance;
		}

		public static function init(pLoader:LoadQeue, pFileName:String = null):void {
			if (instance._inited) return;
			instance._inited = true;
			instance._styleSheet.setLoader(pLoader);
			pLoader.onQeueComplete.add(instance._parseStyles);
			instance._styleSheet.load(pFileName || "uiStyles/uiStyles.css");
		}
		
		public static function setStyles(pStyleSheet:String):void {
			if (instance._inited) return;
			instance._inited = true;
			instance._styleSheet.parse(pStyleSheet);
		}
		
		public static function getBitmapInfo(pBmpUrl:String, pState:String):BitmapInfo {
			return _instance._bmpCache[pBmpUrl+"_"+pState];
		}

		public static function getStyleFor(pComponent:UIComponent, pPseudo:String = null):UIStyle {
			return _instance._getStyleFor(pComponent, pPseudo);
		}

		private function _parseStyles(pSender:LoadQeue, pArgs:EventArgs):void {
			var styles:Array = _styleSheet.listStyles(),
			alreadyProcessed:Object = {};
			
			var bmps:Array= ["borderImage","backgroundImage","arrow1Image","arrow2Image","thumbImage","thumbGlyph"];
			
			for each(var selector:String in styles){
				
				//do not process bitmaps on pseudo selectors but :focus
				if (selector.indexOf(":") != -1 && selector.indexOf(":focus") == -1) continue;
				
				var style:Object = _styleSheet.getStyle(selector);
				
				for each(var imgData:String in bmps){
					var url:String = style[imgData+"Url"];
				
					if (!url || alreadyProcessed[url]) continue;
					
					alreadyProcessed[url] = true;
					
					var p:Point = new Point(0,0),
					bmpData:BitmapData = StyleSheet.getBitmapData(url),
					
					slices:Array = style[imgData+"States"] ? style[imgData+"States"].split("") : ["n"],
					slicesArrayLength:uint = slices.length,
					bmpHeight:uint = (bmpData.height / slicesArrayLength),
					slice9Rect:Rectangle = null;

					if (style[imgData+"Top"]){
						slice9Rect = new Rectangle(
							style[imgData+"Left"],
							style[imgData+"Top"], 
							bmpData.width - style[imgData+"Left"] - style[imgData+"Right"],
							bmpHeight - style[imgData+"Top"] - style[imgData+"Bottom"]
						);
					}
					
					var rx:Boolean = style[imgData+"StrechX"] == "repeat",
					ry:Boolean = style[imgData+"StrechY"] == "repeat",
					
					tx:uint = parseInt(style[imgData+"ThumbX"]),
					ty:uint = parseInt(style[imgData+"ThumbY"]),
					
					lastSliceName:String = null,
					startY:uint = 0;
					
					for (var i:uint = 0; i<slicesArrayLength; ++i){
						var sliceName:String = url + "_"+slices[i],
						tmpBitmap:BitmapData = new BitmapData(bmpData.width, bmpHeight, true, 0xffffff);
						tmpBitmap.copyPixels(bmpData, new Rectangle(0, startY, bmpData.width, bmpHeight), p);
						var bi:BitmapInfo = new BitmapInfo(tmpBitmap, slice9Rect, rx, ry, tx, ty);
						
						if (lastSliceName && BitmapInfo(_bmpCache[lastSliceName]).bmp.compare(tmpBitmap) === 0){
							_bmpCache[sliceName] = _bmpCache[lastSliceName];
							tmpBitmap.dispose();
								 
						} else {
							_bmpCache[sliceName] = bi;
						}
						
						startY += bmpHeight;
						lastSliceName = sliceName;
					}
				}
			}
		}
		
		private function _getStyleFor(pComponent:UIComponent, pPseudo:String):UIStyle {
			var computed:ComputedStyle = _styleSheet.getComputedStyle(pComponent, pPseudo);
			
			if (_styles[computed.fullName]) return _styles[computed.fullName];

			_styles[computed.fullName] = new UIStyle(computed);
			return _styles[computed.fullName];
		}
		
		public function canParse(pProperty:String):Boolean {
			switch (pProperty){
				case "background-image":
				case "border-image":
				case "arrow1-image":
				case "arrow2-image":
				case "arrow1-position":
				case "arrow2-position":
				case "thumb-image":
				case "thumb-glyph":
					return true;
			}
			
			return false;
		}
		
		public function parse(pProperty:String, pValue:String):Array {
			switch (pProperty){
				case "background-image":
				case "border-image":
				case "arrow1-image":
				case "arrow2-image":
				case "thumb-image":
				case "thumb-glyph":
					return _parseImage(pValue, pProperty);
					
				case "arrow1-position":
				case "arrow2-position":
					return _parsePosition(pValue, pProperty);
			}
			
			return null;
		}
		
		private function _parsePosition(pString:String, pAdd:String):Array {
			var parts:Array = pString.split(" ");
			return [
				new ParsedProperty(pAdd+"-left", ParseCommons.parseLength(parts[0])),
				new ParsedProperty(pAdd+"-top", ParseCommons.parseLength(parts[1]))
			];
		}
		
		private function _parseImage(pString:String, pAdd:String):Array {
			var parts:Array = pString.split(","),
			states:String = parts[1] || "n",
			thumbsS:String =  parts[2] || "0 0",
			thumbs:Array = thumbsS.split(" ");
			
			parts = parts[0].split(" ");
			
			return [
					new ParsedProperty(pAdd+"-url", ParseCommons.parseUrl(parts[0]), true),
					new ParsedProperty(pAdd+"-top", parts[1]),
					new ParsedProperty(pAdd+"-right", parts[2]),
					new ParsedProperty(pAdd+"-bottom", parts[3]),
					new ParsedProperty(pAdd+"-left", parts[4]),
					new ParsedProperty(pAdd+"-strech-x", parts[5] || "strech"),
					new ParsedProperty(pAdd+"-strech-y", parts[6] || "strech"),
					new ParsedProperty(pAdd+"-states", states),
					new ParsedProperty(pAdd+"-thumb-x", thumbs[0]),
					new ParsedProperty(pAdd+"-thumb-y", thumbs[1])
			];
		}
	}
}

final class PrivateClass{}
